home *** CD-ROM | disk | FTP | other *** search
- /*
- MakeFunctionPlugin() - create an external plugin for a numerical function
- Version 0.1
- Requires: compiler named "c++" with ELF .so support; Yacas headers in FindFile("")/include; current directory must be writable
- Usage: MakeFunctionPlugin(ExtName, ArgList, Body)
- */
-
- MakeArgumentList(argList, padding) := [ /* may assume to have a nonempty list */
- Local(item, result);
- /* build a list and add commas after 1st element */
- result := padding : String(Head(argList));
- ForEach(item, Tail(argList))
- result := result : "," : padding : String(item);
- result;
- ];
-
- MakeFunctionPrototype(name, argList) := [
- "double " : name : "(" : MakeArgumentList(argList, "double ") : ")";
- ];
-
- MakeFunctionPlugin(extName, fBody) := [
- Local(dirBase, fileBase, intName, exportName, includeDir, dllName, dllPath, commandLine, argList);
- /* check argument type */
- argList := VarList(fBody);
- Check(IsString(extName) And Length(argList) > 0,
- "Error in MakeFunctionPlugin: " : extName
- : " must be a string and " : argList : " a nonempty list.");
- includeDir := FindFile("include/");
- Check(includeDir != "",
- "Error in MakeFunctionPlugin: no include/ under " : FindFile(""));
- /* determine file names */
- dirBase := "plugins.tmp/"; // where all plugin files will be kept
- SystemCall("test -d " : dirBase : "|| mkdir -p " : dirBase);
- fileBase := dirBase : extName : "_plugin";
- intName := extName : "_plugin_cc"; // name of C++ function
- exportName := extName : "_plugin"; // name of intermediate Yacas function
- dllName := "lib" : intName : ".so";
- dllPath := dirBase : dllName;
- /* specify more include dirs to be able to compile from different places */
- commandLine := "c++ -shared -I. -I.. -I" : includeDir : " -I" : includeDir : "plat/linux32 -Wl,-soname," : dllName : " -o " : dllPath : " " : fileBase : ".cc " : fileBase : "_api.cc >& " : fileBase : ".log";
- /* write C++ header */
- ToFile(fileBase : ".h")
- WriteString(
- "// GENERATED FILE: " : fileBase : ".h" : Nl()
- : MakeFunctionPrototype(intName, argList) : ";" : Nl()
- );
- /* write C++ body */
- ToFile(fileBase : ".cc")
- WriteString(
- "// GENERATED FILE: " : fileBase : ".cc" : Nl()
- : "#include \"stubs.h\"" : Nl()
- : "#include \"" : fileBase : ".h\"": Nl()
- : "#include <math.h>" : Nl()
- : "const double Pi=" : CForm(Hold(4.*ArcTan(1.))): ";" : Nl()
- : MakeFunctionPrototype(intName, argList) : " {" : Nl()
- : "return " : CForm(fBody) : ";" : Nl()
- : "}" : Nl()
- );
- /* write Yacas stub */
- ToFile(fileBase : ".stub") [
- WriteString(
- "/* GENERATED FILE: " : fileBase : ".stub */" : Nl()
- : "Use(\"cstubgen.rep/code.ys\"); StubApiCStart();" : Nl()
- : "StubApiCInclude(\"\\\"" : fileBase : ".h\\\"\");" : Nl()
- : "StubApiCFunction(\"double\", \"" : intName : "\", \"" : exportName : "\",");
- Write(FillList("double", Length(argList)));
- WriteString(
- ");" : Nl()
- : "StubApiCFile(\"" : fileBase : "_api\");" : Nl()
- );
- ];
- /* generate C++ stub */
- Load(fileBase : ".stub");
- /* compile plugin for Linux */
- ToFile(fileBase : ".compile") WriteString(commandLine : Nl());
- /* delete old file */
- SystemCall("rm -f " : dllPath);
- SystemCall(commandLine);
- /* If compilation succeeds, DLL file is present */
- Check(FindFile(dllPath) = dllPath, "Error in MakeFunctionPlugin: compilation of " : fileBase : ".so failed.");
- /* Load DLL file */
- DllUnload(dllPath);
- DllLoad(dllPath);
- Echo({"Function " : extName : "(" : MakeArgumentList(argList, ""): ") loaded from " : dllPath});
- /* define wrapper */
- NFunction(extName, exportName, argList);
- ];
-
- /* Example code to read the PID of the Yacas process into the variable PID
- We have to jump through the hoops here because we can't redirect STDOUT to a Yacas stream... ideally it would be just this:
- PID := FromString(ToString() SystemCall("echo $PPID ';'")) Read();
- */
- GetYacasPID() := [
- SystemCall("echo $PPID ';' > /tmp/yacas-tmp");
- FromFile("/tmp/yacas-tmp") Read();
- ];
-
- /* show a Yacas expression graphically in a PS file */
- /* The following global variable will define the available PS viewer */
- If(Not(IsBound(PSViewCommand)), PSViewCommand := "gv");
-
- ShowPS(expr) := [
- /* Create a temporary file */
- SystemCall("echo \\\"/tmp/yacas-tmpfile-$$\\\" ';' > /tmp/yacas-tmp");
- filename := FromFile("/tmp/yacas-tmp") Read();
- SystemCall("rm -f /tmp/yacas-tmp");
- ToFile(filename : ".tex") WriteString(
- "\\documentclass{article} \\begin{document} \\thispagestyle{empty}
- " : TeXForm(expr) : "
- \\end{document}
- ");
- WriteString("Expression exported as " : filename : ".tex" : Nl());
- /* Make PS file */
- SystemCall("cd /tmp; latex " : filename : " > /dev/null; dvips -q -o " : filename : ".ps " : filename : ".dvi");
- /* Show PS file */
- SystemCall(PSViewCommand : " " : filename : ".ps; rm -f " : filename : ".*");
- ];
-